/** 
 * This file is part of osami-fin-demo project( http://code.google.com/p/osami-fin-demo/ )
 * @license Apache License 2.0
 */
package org.osami.appevent;

import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Iterator;

import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;

import android.content.Context;


/** 'typedef' for adding call event properties */
class CallEventProperty extends Hashtable<String, String> {
	private static final long serialVersionUID = 0x1L;
}

/**
 * This is given for Android BroadcastReceivers to allow sending OSGi events and
 * implements the EventAdmin event creation for the phone events.
 * */
public class EventDispatcher {

	public static final String MESSAGE_TYPE_SMS = "org/osami/phone/sms";
	public static final String MESSAGE_TYPE_CALL_INCOMING = "org/osami/phone/callIncoming";
	public static final String MESSAGE_TYPE_CALL_OUTGOING = "org/osami/phone/callOutgoing";

	public static final String CALL_STATE_IDLE = "CALL_STATE_IDLE";
	public static final String CALL_STATE_RINGING = "CALL_STATE_RINGING";
	public static final String CALL_STATE_OFFHOOK = "CALL_STATE_OFFHOOK";

	public static final String PROPERTY_CALL_STATE = "CALLSTATE";
	public static final String PROPERTY_CALLER_NAME = "CALLER_NAME";
	public static final String PROPERTY_CALLER_NUMBER = "CALLER_NUMBER";
	
	public static final String SMS_CONTENTS = "CONTENTS";
	public static final String SMS_SENDER_NAME = "SENDER_NAME";
	public static final String SMS_SENDER_NUMBER = "SENDER_PHONENUMBER";

	protected Logger log;
	protected EventAdmin eventAdmin;
	
	protected Hashtable<String, ServiceRegistration> registeredServices;
	
	public EventDispatcher(EventAdmin aEventAdmin) {
		this.eventAdmin = aEventAdmin;
		this.log = new Logger(this.getClass().getName());
		this.registeredServices = new Hashtable<String, ServiceRegistration>();
	}

	protected void createMessage(String aMsgType,
			Dictionary<String, String> aProperties) {
		log.d("Posting event via EventAdmin:", aMsgType);
		eventAdmin.postEvent(new Event(aMsgType, aProperties));
	}

	public void makeEventCallIncoming(String aCallState, String aCallerNumber,
			String aCallerName) {
		log.d("Creating incoming call event:", aCallState, aCallerNumber);

		CallEventProperty props = new CallEventProperty();
		props.put(PROPERTY_CALL_STATE, aCallState);
		props.put(PROPERTY_CALLER_NAME, aCallerName);
		props.put(PROPERTY_CALLER_NUMBER, aCallerNumber);
		this.createMessage(MESSAGE_TYPE_CALL_INCOMING, props);
	}

	public void makeEventCallOutgoing(String aCallState, String aCallerNumber,
			String aCallerName) {
		CallEventProperty props = new CallEventProperty();
		props.put(PROPERTY_CALL_STATE, aCallState);
		props.put(PROPERTY_CALLER_NAME, aCallerName);
		props.put(PROPERTY_CALLER_NUMBER, aCallerNumber);
		this.createMessage(MESSAGE_TYPE_CALL_OUTGOING, props);
	}

	public void makeEventSMS(String msg, String phoneNumber, String sender) {
		CallEventProperty props = new CallEventProperty();
		props.put(SMS_CONTENTS, msg);
		props.put(SMS_SENDER_NAME, sender);
		props.put(SMS_SENDER_NUMBER, phoneNumber);
		// TODO: Caller\called to?
		this.createMessage(MESSAGE_TYPE_SMS, props);
	}
	
	/** Create an OSGi event from JSON sent from application.
	 * 
	 * @param topic
	 * @param json
	 * @throws JSONException
	 */
	public void makeEventApplication(String topic, JSONObject json) throws JSONException 
	{
		
		CallEventProperty props = new CallEventProperty();
		
		Iterator<String> keys = json.keys();
		while(keys.hasNext()){
			String key = keys.next();
			props.put(key, json.getString(key));
		}
		this.createMessage(topic, props);
	}
	

	/** Request conversion of specific OSGi event to Android Intent.
	 * 
	 * The types of OSGi event properties are limited to serializable and primitive types. 
	 * 
	 * @param topic: OSGi topic to listen
	 * @param intentID: The ID of the Android intent to convert to 
	 * @param androidContext: Android context used to broadcast the Intent.
	 * @param bundleContext: OSGi bundle context to register event handler.
	 * */
	public void requestOSGi2Intent(String topic, String intentAction, Context androidContext, BundleContext bundleContext )
	{
		this.log.df("OSGi->Intent(%s->%s) conversion requested", topic, intentAction);
		
		String[] topics = new String[] {EventConstants.EVENT_TOPIC, topic};
		Hashtable<String,String[]> ht = new Hashtable<String,String[]>();
		ht.put(EventConstants.EVENT_TOPIC, topics);
		
		ServiceRegistration reg = bundleContext.registerService(EventHandler.class.getName(), 
				new OSGi2IntentHandler(androidContext, intentAction), ht);
		
		if(reg != null)
		{
			if(registeredServices.containsKey(intentAction)){
				log.df("Unregistering previous conversion service for Intent %s", intentAction);
				registeredServices.get(intentAction).unregister();
			}
			registeredServices.put(intentAction, reg);
		}
		else{
			log.ef("Failed to register service:%s", topic);
		}
	}
	
	public void unregister(){
		log.d("Unregistering services");
		
		for(String intentAction: registeredServices.keySet() )
		{
			log.df("Unregistering service for Android intent %s", intentAction);
			ServiceRegistration reg = registeredServices.get(intentAction);
			reg.unregister();
		}
	}
}

